package com.xq.tmall.agu.timer;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xq.tmall.agu.core.agent.WebAgent;
import com.xq.tmall.agu.task.EasyCrawl;
import com.xq.tmall.util.DateUtil;
import com.xq.tmall.util.IpFerginUtil;
import com.xq.tmall.util.ProxyUtils;
import com.xq.tmall.util.RedisKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class IpTimer {

    private static final int MAX_RETRY_TIMES = 3; // 最大重试次数
    private static final long RETRY_INTERVAL_MS = 8000; // 重试间隔（毫秒，可调整为指数退避）

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private IpFerginUtil ipFerginUtil;

    /**
     * 9点20，15点，16点执行一次
     */
    @Scheduled(cron = "0 20 9 * * ?")
    public void scheduledTask() {
        if (isWeekend()) {
            log.debug("周末跳过IP验证");
            return;
        }
        LocalTime now = LocalTime.now();
        log.info("执行IP验证任务 ({}:{})", now.getHour(), now.getMinute());
        validateAndUpdateIp();
    }
    @Scheduled(cron = " 0 0 15 * * ?")
    public void scheduledTask2() {
        if (isWeekend()) {
            log.debug("周末跳过IP验证");
            return;
        }
        LocalTime now = LocalTime.now();
        log.info("执行IP验证任务 ({}:{})", now.getHour(), now.getMinute());
        validateAndUpdateIp();
    }

    @Scheduled(cron = "0 0 16 * * ?")
    public void scheduledTask3() {
        if (isWeekend()) {
            log.debug("周末跳过IP验证");
            return;
        }
        LocalTime now = LocalTime.now();
        log.info("执行IP验证任务 ({}:{})", now.getHour(), now.getMinute());
        validateAndUpdateIp();
    }

    private boolean isWeekend() {
        // 使用Java 8的DayOfWeek进行周末判断
        LocalDateTime dateTime = LocalDateTime.now();
        // 周末不执行
        boolean isWeek = DateUtil.isWeekend(dateTime);
        return isWeek;
    }


    private void validateAndUpdateIp() {
        int retryCount = 0;
        boolean success = false;
        while (retryCount < MAX_RETRY_TIMES && !success) {
            try {
                if (redisTemplate.hasKey(RedisKey.PROXY_IP_KEY)) {
                    validateAndUpdateExistingIp(retryCount); // 传入当前重试次数
                } else {
                    fetchAndStoreNewIp(retryCount); // 传入当前重试次数
                }
                success = true; // 执行成功，退出循环
            } catch (Exception e) {
                retryCount++;
                log.warn("IP验证失败，第 {} 次重试（剩余 {} 次）", retryCount, MAX_RETRY_TIMES - retryCount);
                if (retryCount < MAX_RETRY_TIMES) {
                    try {
                        Thread.sleep(RETRY_INTERVAL_MS); // 等待后重试
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                        log.error("重试等待被中断", ie);
                        break;
                    }
                }
            }
        }

        if (!success) {
            log.error("IP验证失败，已达最大重试次数（{}次）", MAX_RETRY_TIMES);
        }
        updateCookies();
    }

    private void validateAndUpdateExistingIp(int retryCount) {
        try {
            String valueKey = (String) redisTemplate.opsForValue().get(RedisKey.PROXY_IP_KEY);
            if (valueKey == null || !valueKey.contains(":")) {
                log.warn("Redis中的代理IP格式无效: {}", valueKey);
                throw new RuntimeException("IP格式无效"); // 触发重试
            }

            String[] parts = valueKey.split(":");
            String redisIp = parts[0];
            String redisPort = parts[1];

            log.info("验证现有代理IP: {}:{}", redisIp, redisPort);

            // 验证HTTP代理
            boolean available = ProxyUtils.validateIp(redisIp, Integer.parseInt(redisPort), ProxyUtils.ProxyType.HTTP);

            // 如果HTTP不可用，尝试HTTPS
            if (!available) {
                log.info("HTTP代理不可用，尝试HTTPS验证");
                available = ProxyUtils.validateIp(redisIp, Integer.parseInt(redisPort), ProxyUtils.ProxyType.HTTPS);
            }

            if (available) {
                log.info("代理IP {}:{} 仍然有效", redisIp, redisPort);
            } else {
                log.info("代理IP已失效，获取新IP");
                throw new RuntimeException("IP验证失败"); // 触发重试
            }
        } catch (Exception e) {
            log.error("验证现有IP失败（第 {} 次重试）", retryCount, e);
            throw e; // 抛出异常，由外层重试逻辑处理
        }
    }

    private void fetchAndStoreNewIp(int retryCount) {
        try {
            log.info("开始获取新代理IP（第 {} 次重试）", retryCount);

            // 调用代理服务获取IP（可能抛出异常）
            String result = new EasyCrawl<String>()
                    .webAgent(WebAgent.defaultAgent().useAgent(ipFerginUtil.getUseAgent()).url(ipFerginUtil.getIpUrl()))
                    .analyze(r -> r.getResult().getBody()).execute();

            log.info("获取IP服务代理响应: {}", result);

            // 解析JSON（可能抛出异常）
            JSONObject jsonObject = JSON.parseObject(result);
            JSONObject ipData = jsonObject.getJSONObject("data");
            JSONArray jsonArray = ipData.getJSONArray("proxy_list");

            if (jsonArray == null || jsonArray.isEmpty()) {
                log.error("未获取到有效的代理IP列表");
                throw new RuntimeException("IP列表为空"); // 触发重试
            }

            String ipPort = jsonArray.getString(0);
            String[] parts = ipPort.split(":");

            if (parts.length < 2) {
                log.error("无效的IP端口格式: {}", ipPort);
                throw new RuntimeException("IP格式无效"); // 触发重试
            }

            String ip = parts[0];
            String port = parts[1];

            log.info("获取到新代理IP: {}:{}", ip, port);

            // 存储到Redis
            ValueOperations<String, Object> valueOps = redisTemplate.opsForValue();
            valueOps.set(RedisKey.PROXY_IP_KEY, ipPort);
            redisTemplate.expire(RedisKey.PROXY_IP_KEY, 60, TimeUnit.MINUTES);
            log.info("新代理IP已存储到Redis");
        } catch (Exception e) {
            log.error("获取新IP失败（第 {} 次重试）", retryCount, e);
            throw e; // 抛出异常，由外层重试逻辑处理
        }
    }

    private void updateCookies() {
        try {
            String cookieUrl = "https://xueqiu.com/about/contact-us";
            log.info("开始更新Cookies");

            // 检查Redis中是否有Cookies
            if (!redisTemplate.hasKey(RedisKey.PROXY_COOKIES)) {
                Map<String, String> cookies = WebAgent.getCookies(cookieUrl);

                if (cookies != null && !cookies.isEmpty()) {
                    redisTemplate.opsForHash().putAll(RedisKey.PROXY_COOKIES, cookies);
                    redisTemplate.expire(RedisKey.PROXY_COOKIES, 60, TimeUnit.MINUTES);
                    log.info("Cookies已更新并存储到Redis");
                } else {
                    log.warn("未获取到Cookies");
                }
            } else {
                log.info("Cookies已存在，无需更新");
            }
        } catch (Exception e) {
            log.error("更新Cookies失败", e);
        }
    }
}
